package hu.myai.util.pool;

import hu.myai.api.indicators.IndicatorInterface;
import hu.myai.api.tick.AbstractTickProvider;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author bozbalint
 *
 */
public class IndicatorPool {

    /**
     * The object used when logging debug,errors,warnings and info.
     * */
    private static Logger log = LoggerFactory.getLogger("IndicatorPool");

    /**
     * the indicator pool grouped by tick
     * */
    private static Map<String, Map<String, IndicatorInterface>> tickGroup = new HashMap<String, Map<String, IndicatorInterface>>();

    /**
     * the tick pool
     * */
    private static Map<String, AbstractTickProvider> tickMap = new HashMap<String, AbstractTickProvider>();

    /**
     * For registering an indicator to the pool. If same indicator already in the pool
     * than return the one from the pool
     * */
    public static synchronized IndicatorInterface indicatorManager(IndicatorInterface indicator,
            AbstractTickProvider tick) {

        String tickName = tick.getName();

        if (!tickMap.containsKey(tickName)) {
            tickMap.put(tickName, tick);
        }

        return indicatorManager(indicator, tickName);
    }

    /**
     * For register an indicator to the pool. If same indicator already in the pool
     * than return the one from the pool
     * */
    public static synchronized IndicatorInterface indicatorManager(IndicatorInterface indicator, String tickName) {

        // get the appropriate pool if more than one available
        Map<String, IndicatorInterface> indicatorPool = getTickGroup(tickName);

        Double indicatorParam = indicator.getParameter();

        // key is generated from indicator name and parameter
        String indicatorKey = indicator.getClass().getCanonicalName() + "_" + indicatorParam;

        // check the indication if in the pool or need to register
        if (indicatorPool.containsKey(indicatorKey)) {

            // well known indicator nothing to do
        	indicator = indicatorPool.get(indicatorKey);
        } else {
            indicatorPool.put(indicatorKey, indicator);

            // register the indicator into the tick
            if (tickMap.get(tickName) != null) {
                tickMap.get(tickName).addTickConsumer(indicator);
            } else {
                log.error("Error - tick cannot be null, not possible to register into it: " + indicatorKey);
            }

            // set the indicator
            indicator.init(indicatorKey, tickName);
        }

        return indicator;
    }

    /**
     * Get the tick specified indicator group. If no tick specified indicator
     * group than creates it.
     * */
    private synchronized static Map<String, IndicatorInterface> getTickGroup(String tickName) {

        // check the tick if in the pool or need to register
        if (tickGroup.containsKey(tickName)) {
            return tickGroup.get(tickName);
        } else {
            Map<String, IndicatorInterface> indicatorMap = new HashMap<String, IndicatorInterface>();
            tickGroup.put(tickName, indicatorMap);
            return indicatorMap;
        }
    }

    /**
     * return the list of registered indicators
     * */
    public synchronized static List<IndicatorInterface> getIndicatorList(String tickName) {
        if (tickGroup.get(tickName) != null) {
            Collection<IndicatorInterface> values = tickGroup.get(tickName).values();
            return new ArrayList<IndicatorInterface>(values);
        } else {
            assert false;
            log.error("Error - " + tickName + " is not valid pool key");
            return new ArrayList<IndicatorInterface>();
        }
    }

    /**
     * clear the indicator pool
     * */
    public synchronized static void clear(String tickName) {
        // remove the tick
    	if(tickMap.containsKey(tickName))
        	tickMap.remove(tickName);

    	// remove the registered indicators
        if (tickGroup.containsKey(tickName))
            tickGroup.remove(tickName);
    }
}
